/**
 * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
 */

package net.sourceforge.pmd.eclipse.util;

import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.graphics.TextLayout;
import org.eclipse.swt.graphics.TextStyle;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;

import net.sourceforge.pmd.Rule;
import net.sourceforge.pmd.eclipse.ui.IndexedString;
import net.sourceforge.pmd.eclipse.ui.preferences.br.RuleFieldAccessor;

public class StyledTextBuilder extends AbstractCellPainterBuilder {

    private Display display = Display.getDefault(); // NOPMD by br on 2/22/11 11:22 PM
    private TextLayout layout = new TextLayout(display);
    private final TextStyle style;

    public StyledTextBuilder(final FontBuilder theBuilder) {
        style = theBuilder.style(display);
    }

    private Font adjust(TreeItem tItem, RuleFieldAccessor getter, Tree tree) {

        Object value = valueFor(tItem, getter);

        IndexedString is = (IndexedString) value;
        String text = value == null ? "" : is.string;

        Rule rule = ruleFrom(tItem);
        if (rule != null) {
            style.font = fontFor(tree, rule);
        }
        layout.setText(text);

        if (StringUtils.isBlank(text)) {
            layout.setStyle(style, 0, 0);
        } else {
            for (int i = 0; i < is.indexSpans.size(); i++) {
                layout.setStyle(style, is.indexSpans.get(i)[0], is.indexSpans.get(i)[1] - 1);
            }
        }

        return style.font;
    }

    @Override
    public void addPainterFor(final Tree tree, final int columnIndex, final RuleFieldAccessor getter,
            Map<Integer, List<Listener>> listenersByEventCode) {

        Listener paintListener = new Listener() {
            @Override
            public void handleEvent(Event event) {
                if (event.index != columnIndex) {
                    return;
                }

                Font font = adjust((TreeItem) event.item, getter, tree);
                event.gc.setFont(font);
                layout.setFont(font);
                int descent = event.gc.getFontMetrics().getDescent();

                layout.draw(event.gc, event.x, event.y + descent);
            }
        };

        Listener measureListener = new Listener() {
            @Override
            public void handleEvent(Event event) {
                if (event.index != columnIndex) {
                    return;
                }

                adjust((TreeItem) event.item, getter, tree);

                final Rectangle textLayoutBounds = layout.getBounds();
                event.width = textLayoutBounds.width + 2;
                event.height = textLayoutBounds.height + 2;
            }
        };

        addListener(tree, SWT.PaintItem, paintListener, listenersByEventCode);
        addListener(tree, SWT.MeasureItem, measureListener, listenersByEventCode);
    }
}
